home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Graphics 2D / Restore Screen Cluts / ColorReset.c next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  45.2 KB  |  1,284 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        ColorReset.c
  3.  
  4.     Contains:    Main program file
  5.  
  6.     Written by: Forrest Tanaka    
  7.  
  8.     Copyright:    Copyright © 1988-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 7/13/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23.  
  24. /******************************************************************************\
  25. * Header Files
  26. \******************************************************************************/
  27.  
  28. #include <Desk.h>
  29. #include <DiskInit.h>
  30. #include <Errors.h>
  31. #include <Fonts.h>
  32. #include <Menus.h>
  33. #include <Resources.h>
  34. #include <ToolUtils.h>
  35. #include <QuickDraw.h>
  36. #include <Windows.h>
  37. #include <Events.h>
  38. #include <OSEvents.h>
  39. #include <AppleEvents.h>
  40. #include <GestaltEqu.h>
  41. #include <Packages.h>
  42. #include <Palettes.h>
  43. #include <Traps.h>
  44. #include <TextUtils.h>
  45.  
  46. #include "EmergMem.h"
  47. #include "ColorReset.h"
  48. #include "MenuHandler.h"
  49. #include "PictDocument.h"
  50. #include "WindowPositioner.h"
  51.  
  52. #ifndef topLeft
  53. #define topLeft(r)                      (((Point *) &(r))[0])
  54. #endif
  55.  
  56. #ifndef botRight
  57. #define botRight(r)                     (((Point *) &(r))[1])
  58. #endif
  59.  
  60.  
  61. /******************************************************************************\
  62. * Constants
  63. \******************************************************************************/
  64.  
  65. /* Disk initialization */
  66. #define kSysAlertLeft 80 /* Left coord of DIBadMount alert in screen coords */
  67. #define kSysAlertTop  80 /* Top coord of DIBadMount alert in screen coords */
  68.  
  69. /* EqualString convenience constants */
  70. #define kCaseSens true /* Pass to EqualString for case-sensitive check */
  71. #define kDiacSens true /* Pass to EqualString for diacritical-sens. check */
  72.  
  73. /* Constants for checking on command-. */
  74. #define kMaskModifiers 0xFE00     /* Mask for modifiers w/o command key */
  75. #define kMaskASCII1    0x00FF0000 /* get the key out of the ASCII1 byte */
  76. #define kMaskASCII2    0x000000FF /* get the key out of the ASCII2 byte */
  77.  
  78. /* Miscellaneous */
  79. #define kMinWindSize    128  /* Minimum size of a window */
  80. #define kMaxSleepTime   60   /* # ticks to wait between minor switches */
  81. #define kBecomingActive true /* Pass to DoActivateEvt; app becoming active */
  82.  
  83.  
  84. /******************************************************************************\
  85. * Macros
  86. \******************************************************************************/
  87.  
  88. /* Return status of bth bit of m */
  89. #define btst(m,b) ((m) & (1L << (b)))
  90.  
  91.  
  92. /******************************************************************************\
  93. * Global Variables
  94. \******************************************************************************/
  95.  
  96. Boolean gHasWNE;         /* True if WaitNextEvent is implemented */
  97. Boolean gQuitting;       /* True if user requested that this app quit */
  98. Boolean gWereInFront;    /* True if this application is frontmost */
  99. Boolean gFixMenus;       /* True if menus need fixing */
  100. Boolean gHasAppleEvents; /* True if Apple Events implemented */
  101. Boolean gHasCoolSF;      /* True if 7.0 Standard File routines available */
  102.  
  103. ControlActionUPP gActionProc;
  104.  
  105. QDBitsUPP        gQDBitsUPP;
  106. QDGetPicUPP      gQDGetPicUPP;
  107. QDPutPicUPP      gQDPutPicUPP;
  108.  
  109. #ifdef powerc
  110.    QDGlobals    qd;
  111. #endif
  112.  
  113.  
  114.  
  115. /******************************************************************************\
  116. * Private Function Prototypes
  117. \******************************************************************************/
  118.  
  119. main(void);
  120.  
  121. void StartUp(void);
  122.  
  123. void ShutDown(void);
  124.  
  125. void EventLoop(void);
  126.  
  127. long CalcSleepTime(void);
  128.  
  129. void DoMouseDown(EventRecord *anEvent);
  130.  
  131. void DoKeyDown(EventRecord *anEvent);
  132.  
  133. void DoDiskEvt(EventRecord *anEvent);
  134.  
  135. OSErr HandleAEquit(AppleEvent *quitAppleEvent,AppleEvent *reply, long  handlerRefCon);
  136.  
  137. OSErr DoneRequiredParams(AppleEvent *anAppleEvent);
  138.  
  139. Boolean IsDAWindow(WindowPtr aWindow);
  140.  
  141. void DoWindowDrag(EventRecord *anEvent,WindowPtr   clickedWindow);
  142.  
  143. void DoWindowGrow(EventRecord *anEvent,WindowPtr   clickedWindow);
  144.  
  145. void DoContentClick(EventRecord *anEvent,WindowPtr   clickedWindow);
  146.  
  147. void DoActivateEvt(WindowPtr eventWind,Boolean   becomingActive);
  148.  
  149. void DoWindowClose(EventRecord *anEvent,WindowPtr   eventWindow);
  150.  
  151. short MaxToolboxTrap(void);
  152.  
  153. TrapType GetTrapType(short theTrap);
  154.  
  155.  
  156. /******************************************************************************\
  157. * Public: main - Entry point to this application
  158. *
  159. * After the heap is initialized by allocating several master pointer blocks and
  160. * expanding the application’s heap to its maximum size, StartUp is called to
  161. * complete initialization.  The user is asked to open a Picture Document, and
  162. * then the main event loop is entered.
  163. \******************************************************************************/
  164.  
  165.  
  166. main()
  167. {
  168.     /* Prepare the heap */
  169.     MaxApplZone();
  170.     MoreMasters();
  171.     MoreMasters();
  172.     MoreMasters();
  173.     MoreMasters();
  174.     MoreMasters();
  175.     MoreMasters();
  176.     MoreMasters();
  177.     MoreMasters();
  178.  
  179.     /* Initialize the application */
  180.     StartUp();
  181.     
  182.     /* set up the ControlActionUPP */
  183.     gActionProc = NewControlActionProc((ProcPtr)ScrollActionProc);
  184.     
  185.     /* now set up the UPPs for QDProcs we use */
  186.     gQDBitsUPP   =  NewQDBitsProc(InfoBits);
  187.     gQDGetPicUPP =    NewQDGetPicProc(FileGetPic);
  188.     gQDPutPicUPP =    NewQDPutPicProc(FilePutPic);
  189.  
  190.     /* Ask the user for a Picture Document to open */
  191.     (void)DoOpenPictDoc();
  192.  
  193.     /* Execute the main event loop */
  194.     EventLoop();
  195.  
  196.     /* Shut down the application */
  197.     ShutDown();
  198.  
  199.     /* Return the ANSI way */
  200.     return 0;
  201. }
  202.  
  203.  
  204. /******************************************************************************\
  205. * StartUp - Do whatever has to be done to initialize the application
  206. *
  207. * This routine is called after the heap is initialized to initialize the
  208. * application.  This involves initializing the toolbox, emergency memory,
  209. * loading up the menus, validating the current environment, and initializing
  210. * global variables.  If any errors occur while doing this, StartUp displays
  211. * an alert telling the user what the error was and then ExitToShell is called.
  212. * This is an unusual way to react to errors, and I only do it here because it’s
  213. * so early in execution that there really isn’t much else that can be done.
  214. *
  215. * See EmergMem.h in this application for details about emergency memory.
  216. \******************************************************************************/
  217.  
  218.  
  219. void StartUp()
  220. {
  221.     long         aeAttrs; /* AppleEvent attributes */
  222.     long         sfAttrs; /* Standard File attributes */
  223.     OSErr        error;
  224.     /* Initialize the toolbox */
  225.     InitGraf(&qd.thePort);
  226.     InitFonts();
  227.     InitWindows();
  228.     InitMenus();
  229.     TEInit();
  230.     InitDialogs( nil );
  231.  
  232.     /* Initialize emergency memory */
  233.     InitEmergMem();
  234.     if (FailLowMemory( 0 ))
  235.         SysError(memFullErr);
  236.  
  237.     /* Initialize the menus */
  238.     error = StartMenus();
  239.     if (error !=noErr)
  240.         SysError(error);
  241.         
  242.  
  243.     /* Load and lock the disk-initialization package */
  244.     DILoad();
  245.  
  246.     /* See if WaitNextEvent is implemented */
  247.     gHasWNE = TrapExists( _WaitNextEvent );
  248.  
  249.     /* Check for the fancier capabilities */
  250.     error = Gestalt( gestaltAppleEventsAttr, /*<*/&aeAttrs );
  251.     if (error != noErr)
  252.         gHasAppleEvents = false;
  253.     else
  254.         gHasAppleEvents = btst( aeAttrs, gestaltAppleEventsPresent );
  255.     error = Gestalt( gestaltStandardFileAttr, /*<*/&sfAttrs );
  256.     if (error != noErr)
  257.         gHasCoolSF = false;
  258.     else
  259.         gHasCoolSF = btst( sfAttrs, gestaltStandardFile58 );
  260.  
  261.     /* Install the AppleEvent handler */
  262.     if (gHasAppleEvents)
  263.     {
  264.         error = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication,
  265.                 NewAEEventHandlerProc(HandleAEquit), 0, false );
  266.         if (error != noErr)
  267.             SysError(error);
  268.     }
  269. }
  270.  
  271.  
  272. /******************************************************************************\
  273. * ShutDown - Do whatever has to be done to shut down the application
  274. *
  275. * This routine is called when the application is about to shut down.  It calls
  276. * ExitGraphics and ExitPrinting to shut down Sarano graphics and printing.
  277. \******************************************************************************/
  278.  
  279. static void ShutDown()
  280. {
  281. }
  282.  
  283.  
  284. /******************************************************************************\
  285. * EventLoop - Main event loop for this application
  286. *
  287. * This is the main event loop of this application.  During every iteration of
  288. * the event loop, the menus are kept up-to-date.  Also, NoEmergMem is called to
  289. * detect whether the emergency memory was used.  If it was, then RecoverEmergMem
  290. * is called in an attept to get it back.  If it can’t, then some commands could
  291. * be disabled until the memory can be recovered.
  292. \******************************************************************************/
  293.  
  294. static void EventLoop()
  295. {
  296.     EventRecord anEvent;     /* An incoming event */
  297.     Boolean     gotEvent;    /* True if a non-null event was received */
  298.     WindowPtr   lastWindow;  /* Pointer to front window during last iteration */
  299.     WindowPtr   currWindow;  /* Pointer to the current front window */
  300.     WindowPtr   eventWindow; /* Window involved in an incoming event */
  301.     Byte        osEvtKind;   /* Kind of OSEvt; mouse-moved or suspend/resume */
  302.  
  303.     gWereInFront = true;
  304.     gQuitting = false;
  305.     gFixMenus = true;
  306.     lastWindow = nil;
  307.     InitCursor();
  308.  
  309.     /* We loop until gQuitting is true */
  310.     while (!gQuitting)
  311.     {
  312.         /* Try to reallocate emergency memory if it’s been used */
  313.         if (NoEmergMem())
  314.             RecoverEmergMem();
  315.  
  316.         /* Fix the menus to reflect current conditions */
  317.         currWindow = FrontWindow();
  318.         if (currWindow != lastWindow || gFixMenus)
  319.         {
  320.             FixMenus();
  321.             lastWindow = currWindow;
  322.             gFixMenus = false;
  323.         }
  324.  
  325.         /* It’s time to get and examine an event */
  326.         if (gHasWNE)
  327.             gotEvent = WaitNextEvent( everyEvent, /*<*/&anEvent,
  328.                     CalcSleepTime(), nil );
  329.         else
  330.         {
  331.             SystemTask();
  332.             gotEvent = GetNextEvent( everyEvent, /*<*/&anEvent );
  333.         }
  334.         if (gotEvent)
  335.             switch (anEvent.what)
  336.             {
  337.                 case mouseDown:
  338.                     DoMouseDown( &anEvent );
  339.                     break;
  340.                 case keyDown:
  341.                 case autoKey:
  342.                     DoKeyDown( &anEvent );
  343.                     break;
  344.                 case updateEvt:
  345.                     DoUpdateEvt( &anEvent );
  346.                     break;
  347.                 case diskEvt:
  348.                     DoDiskEvt( &anEvent );
  349.                     break;
  350.                 case activateEvt:
  351.                     DoActivateEvt( (WindowPtr)anEvent.message,
  352.                             anEvent.modifiers & activeFlag );
  353.                     break;
  354.                 case kHighLevelEvent:
  355.                     (void)AEProcessAppleEvent( &anEvent );
  356.                     break;
  357.                 case osEvt:
  358.                     osEvtKind = (anEvent.message >> 24) & 0x0FF;
  359.                     if (osEvtKind == suspendResumeMessage)
  360.                     {
  361.                         /* It’s a suspend/resume event; suspend or resume? */
  362.                         eventWindow = FrontWindow();
  363.                         if ((anEvent.message & 1) != 0)
  364.                         {
  365.                             /* Resume event; set the cursor and activate front window */
  366.                             InitCursor();
  367.                             if (eventWindow != nil)
  368.                                 DoActivateEvt( eventWindow, kBecomingActive );
  369.                             gWereInFront = true;
  370.                             }
  371.                         else
  372.                         {
  373.                             /* Suspend event; deactivate the front window */
  374.                             if (eventWindow != nil)
  375.                                 DoActivateEvt( eventWindow, !kBecomingActive );
  376.                             gWereInFront = false;
  377.                         }
  378.                     }
  379.                     break;
  380.             }
  381.     }
  382. }
  383.  
  384.  
  385. /******************************************************************************\
  386. * CalcSleepTime - Calculate the number of ticks for WaitNextEvent to sleep
  387. *
  388. * WaitNextEvent takes a parameter that specifies the number of ticks that this
  389. * application allows WaitNextEvent to service other open applications.  This is
  390. * just a guideline; the actual amount of time that WaitNextEvent takes could be
  391. * shorter or longer than our specification, depending on how heavy the system
  392. * load is and on how long other applications take.
  393. *
  394. * If the front window is a desk accessory window, CalcSleepTime returns 0 which
  395. * specifies that this application wants as much time as possible.  Under
  396. * MultiFinder, desk accessories are normally running in the DA Handler layer,
  397. * so this really doesn’t matter that much.  Under system software version 7.0,
  398. * desk accessories never run in our layer, so this code never gets executed.
  399. \******************************************************************************/
  400.  
  401. static long CalcSleepTime()
  402. {
  403.     long sleepTime; /* Number of ticks to sleep */
  404.  
  405.     if (IsDAWindow( FrontWindow() ))
  406.         sleepTime = 0;
  407.     else
  408.         sleepTime = kMaxSleepTime;
  409.  
  410.     return sleepTime;
  411. }
  412.  
  413.  
  414. /******************************************************************************\
  415. * DoMouseDown - Mouse-down event dispatcher
  416. *
  417. * When a mouseDown event is received in the main event loop, this routine is
  418. * called to determine which area on the screens the mouseDown was, and to
  419. * dispatch to the appropriate routine to handle mouseDown events in that area.
  420. * The mouseDown event is passed in the anEvent parameter.
  421. *
  422. * See MenuHandler.h for routines that handle mouse-down events in the menu bar.
  423. \******************************************************************************/
  424.  
  425. static void DoMouseDown(
  426.     EventRecord *anEvent) /* Contains mouse-down event */
  427. {
  428.     short     clickArea;   /* Area of the screen that was clicked */
  429.     WindowPtr eventWindow; /* Pointer the clicked window, if any */
  430.  
  431.     /* Find clicked area of screen or window */
  432.     clickArea = FindWindow( anEvent->where, /*<*/&eventWindow );
  433.  
  434.     /* Jump to mouseDown-handling routine appropriate for screen area */
  435.     switch (clickArea)
  436.     {
  437.         case inMenuBar:
  438.             DoMenuChoice( MenuSelect( anEvent->where ) );
  439.             break;
  440.         case inSysWindow:
  441.             SystemClick( anEvent, eventWindow );
  442.             break;
  443.         case inContent:
  444.             DoContentClick( anEvent, eventWindow );
  445.             break;
  446.         case inDrag:
  447.             DoWindowDrag( anEvent, eventWindow );
  448.             break;
  449.         case inGrow:
  450.             DoWindowGrow( anEvent, eventWindow) ;
  451.             break;
  452.         case inGoAway:
  453.             DoWindowClose( anEvent, eventWindow );
  454.             break;
  455.         default:
  456.             break;
  457.     }
  458. }
  459.  
  460.  
  461. /******************************************************************************\
  462. * DoKeyDown - Key-down event dispatcher
  463. *
  464. * When a keyDown or autoKey event is received in the main event loop, this
  465. * routine is called to determine whether key is a command-key equivalent for a
  466. * menu item or not.  If the command key isn’t down, then the key stroke is
  467. * ignored.  Otherwise, MenuKey is called to get the menu ID and item number
  468. * of the menu item that corresponds to the command key, if any.  Then
  469. * DoMenuChoice is called to dispatch to the appropriate routine for the chosen
  470. * menu item.  The keyDown or autoKey event is passed in anEvent.
  471. \******************************************************************************/
  472.  
  473. static void DoKeyDown(
  474.     EventRecord *anEvent) /* Contains the key-down event */
  475. {
  476.     char theKey; /* ASCII code of key that was pressed */
  477.  
  478.     /* Get the ASCII code of the pressed key */
  479.     theKey = anEvent->message & charCodeMask;
  480.  
  481.     /* If anEvent was keyDown and command key was down, it’s menu command */
  482.     if (anEvent->what == keyDown && (anEvent->modifiers & cmdKey))
  483.         DoMenuChoice( MenuKey( theKey ) );
  484. }
  485.  
  486.  
  487. /******************************************************************************\
  488. * DoDiskEvt - Handle a disk-insert event
  489. *
  490. * This routine is called whenever this application receives an event indicating
  491. * that a disk was inserted.  If the disk can’t be mounted, the message field of
  492. * the event reflects the error, and we call DIBadMount to allow the user to
  493. * format the disk.
  494. \******************************************************************************/
  495.  
  496. static void DoDiskEvt(
  497.     EventRecord *anEvent) /* Disk-insert event */
  498. {
  499.     Point cornerPoint; /* Top-left corner of DIBadMount alert */
  500.  
  501.     if (hiWord( anEvent->message ) != noErr)
  502.     {
  503.         SetPt( /*<*/&cornerPoint, kSysAlertLeft, kSysAlertTop );
  504.         (void)DIBadMount( cornerPoint, anEvent->message );
  505.     }
  506. }
  507.  
  508.  
  509. /******************************************************************************\
  510. * Private: HandleAEquit - Handler for 'quit' AppleEvent
  511. *
  512. * This is the AppleEvent handler for the 'quit' AppleEvent as passed in the
  513. * quitAppleEvent parameter by the AppleEvent Manager.  The DoQuit routine is
  514. * called which causes this application to quit at the start of the next
  515. * iteration of the main event loop.
  516. *
  517. * Though the quit AppleEvent doesn’t contain any parameters, the standard thing
  518. * to do in reaction to any AppleEvent is to check to see if there are any
  519. * required parameters in the AppleEvent that this routine doesn’t recognise.
  520. * DoneRequiredParms checks for this condition and returns an error if there are
  521. * in fact required parameters in the AppleEvent or if some other error occurs
  522. * during the check.
  523. \******************************************************************************/
  524.  
  525. static      OSErr HandleAEquit(
  526.     AppleEvent *quitAppleEvent, /* Contains the ‘quit’ AppleEvent */
  527.     AppleEvent *reply,          /* Returns reply; ignored */
  528.     long       handlerRefCon)   /* Application-defined parameter; ignored */
  529. {
  530. #pragma unused(reply,handlerRefCon)
  531.     OSErr error;
  532.  
  533.     /* quit AE has no parms, but check in case the client requires any */
  534.     error = DoneRequiredParams( quitAppleEvent );
  535.     if (error == noErr)
  536.         /* No extra parameters; handle Quit command */
  537.         DoQuit();
  538.  
  539.     return error;
  540. }
  541.  
  542.  
  543. /******************************************************************************\
  544. * DoneRequiredParams - Done processing required params; OK?
  545. *
  546. * DoneRequiredParams checks to see if the AppleEvent specified by the
  547. * anAppleEvent parameter has any required parameters that we haven’t yet
  548. * processed.  If there aren’t any left, then noErr is returned.  If there are
  549. * required parameters that haven’t been processed yet, then errAEEventNotHandled
  550. * is returned.  If any other errors occur, then that error code is returned.
  551. \******************************************************************************/
  552.  
  553. static OSErr DoneRequiredParams(
  554.     AppleEvent *anAppleEvent) /* AppleEvent being checked */
  555. {
  556.     DescType typeCode;   /* Type of AppleEvent attribute found; ignored */
  557.     Size     actualSize; /* Actual size of parameters; ignored */
  558.     OSErr    error;
  559.  
  560.     /* Are there any required parameters in AppleEvent we didn’t process? */
  561.        error = AEGetAttributePtr(
  562.                anAppleEvent,
  563.             keyMissedKeywordAttr,
  564.             typeWildCard,
  565.             /*<*/&typeCode,
  566.             nil,
  567.             0,
  568.             /*<*/&actualSize );
  569.     if (error == errAEDescNotFound)
  570.         /* No required parameters left, so no error */
  571.         error = noErr;
  572.     else if (error == noErr)
  573.         /* There was at least one required parameter we didn’t process */
  574.         error = errAEEventNotHandled;
  575.  
  576.     return error;
  577. }
  578.  
  579.  
  580. /******************************************************************************\
  581. * Public: DoQuit
  582. *
  583. * Each open window is checked to see what kind it is.  If a window is a
  584. * Document window, DoCloseDoc is called to close it.  If the window is a
  585. * desk accessory’s window, then CloseDeskAcc is called to close it.  This
  586. * process continues until all windows are closed.  Then the gQuitting global
  587. * variable is set to true, terminating the main event loop.
  588. \******************************************************************************/
  589.  
  590. void DoQuit()
  591. {
  592.     WindowPtr aWindow; /* Pointer to each window in the window list */
  593.  
  594.     aWindow = FrontWindow();
  595.  
  596.     /* Keep closing a window until there are no windows left */
  597.     while (aWindow != nil)
  598.     {
  599.         if (IsDAWindow( aWindow ))
  600.             CloseDeskAcc( ((WindowPeek)aWindow)->windowKind );
  601.         else
  602.             CloseWindow( aWindow );
  603.         aWindow = FrontWindow();
  604.     }
  605.  
  606.     /* Tell the main event loop that we’re done */
  607.     gQuitting = true;
  608. }
  609.  
  610.  
  611. /******************************************************************************\
  612. * Public: IsDAWindow
  613. *
  614. * The windowKind field of any window belonging to a desk accessory is negative,
  615. * so that’s how IsDAWindow decides whether a window belongs to a desk accessory
  616. * or not.
  617. \******************************************************************************/
  618.  
  619. Boolean IsDAWindow(
  620.     WindowPtr aWindow) /* Pointer to the window being tested */
  621. {
  622.     if (aWindow == nil)
  623.         return false;
  624.     else
  625.         return ((WindowPeek)aWindow)->windowKind < 0;
  626. }
  627.  
  628.  
  629. /******************************************************************************\
  630. * Private: DoWindowDrag - Allow the user to drag a window around
  631. *
  632. * When it’s been detected that the user clicked in the title bar of a window,
  633. * DoWindowDrag is called.  It allows the user to drag a window over the entire
  634. * desktop area, and the window is moved to wherever the user let it go.  Windows
  635. * behind the front window can be dragged as well, unless the front window is a
  636. * modal dialog box.
  637. *
  638. * The mouseDown event that turned out to be a request to drag the window is
  639. * passed in the anEvent parameter.  A pointer to the window whose title bar got
  640. * clicked is passed in clickedWindow.
  641. *
  642. * A rectangle that covers all screen can be retrieved from the desktop region’s
  643. * rgnBBox.  The desktop region can be retrieved by calling GetGrayRgn.
  644. \******************************************************************************/
  645.  
  646. static void DoWindowDrag(
  647.     EventRecord *anEvent,      /* Mouse-down event in the title bar */
  648.     WindowPtr   clickedWindow) /* Pointer to the window that was clicked */
  649. {
  650.     Rect dragBounds; /* Window can be dragged over this rectangle */
  651.  
  652.     /* (**GetGrayRgn()).rgnBBox covers the desktop over all screens */
  653.     dragBounds = (**GetGrayRgn()).rgnBBox;
  654.     DragWindow( clickedWindow, anEvent->where, &dragBounds );
  655. }
  656.  
  657.  
  658. /******************************************************************************\
  659. * Private: DoWindowGrow - Handle a mouse click in the grow box of a window
  660. *
  661. * When it’s been detected that the user clicked in the grow box of a window,
  662. * DoWindowGrow is called.  It allows the user to change the size of the clicked
  663. * window.
  664. *
  665. * The mouseDown event that turned out to be a request to resize the window is
  666. * passed in the anEvent parameter.  A pointer to the window whose grow box got
  667. * clicked is passed in clickedWindow.
  668. \******************************************************************************/
  669.  
  670. static void DoWindowGrow(
  671.     EventRecord *anEvent,      /* Mouse-down event in the title bar */
  672.     WindowPtr   clickedWindow) /* Pointer to the window that was clicked */
  673. {
  674.     /* Have the window react to the resize */
  675.     if (IsPictDocWindow( clickedWindow ))
  676.         GrowPictDoc( clickedWindow, anEvent );
  677. }
  678.  
  679.  
  680. /******************************************************************************\
  681. * Private: DoContentClick - Handle a click in a window
  682. *
  683. * When it’s been detected that the user clicked in the content region of a
  684. * window, DoContentClick is called.  This routine determines the kind of window
  685. * that was clicked and dispatches control to the routine that handles mouse
  686. * clicks in that kind of window.
  687. *
  688. * The mouseDown event that turned out to be a window content click is passed
  689. * in the anEvent parameter.  A pointer to the window whose content region got
  690. * clicked is passed in clickedWindow.
  691. *
  692. * As new kinds of windows are added to this application, this routine will have
  693. * to be able to detect the new kind of window and dispatch to the routine that
  694. * handles clicks in that kind of window.
  695. \******************************************************************************/
  696.  
  697. static void DoContentClick(
  698.     EventRecord *anEvent,      /* Mouse-down event in the window’s content */
  699.     WindowPtr   clickedWindow) /* Pointer to the window that was clicked */
  700. {
  701. #pragma unused(anEvent)
  702.     WindowPtr currWindow; /* Pointer to the current front window */
  703.  
  704.     currWindow = FrontWindow();
  705.  
  706.     /* Clicked window not in front; activate it */
  707.     if (currWindow != clickedWindow)
  708.         SelectWindow( clickedWindow );
  709.     else
  710.     {
  711.         if (IsPictDocWindow( clickedWindow ))
  712.             ClickPictDoc( clickedWindow, anEvent );
  713.     }
  714. }
  715.  
  716.  
  717. /******************************************************************************\
  718. * Public: DoUpdateEvt
  719. *
  720. * As new kinds of windows are added to this application, this routine will have
  721. * to be able to detect the new kind of window and dispatch to the routine that
  722. * handles update events in that kind of window.
  723. \******************************************************************************/
  724.  
  725. void DoUpdateEvt(
  726.     EventRecord *anEvent) /* Update event */
  727. {
  728.     WindowPtr eventWindow; /* Pointer to the window to update */
  729.  
  730.     /* Get a pointer to the window that needs an update */
  731.     eventWindow = (WindowPtr)anEvent->message;
  732.  
  733.     /* Update the window that needs it */
  734.     SetPort( eventWindow );
  735.     BeginUpdate( eventWindow );
  736.     if (IsPictDocWindow( eventWindow ))
  737.         DrawPictDoc( eventWindow );
  738.     EndUpdate( eventWindow );
  739. }
  740.  
  741.  
  742. /******************************************************************************\
  743. * Public: DoActivateEvt
  744. *
  745. * As new kinds of windows are added to this application, this routine will have
  746. * to be able to detect the new kind of window and dispatch to the routine that
  747. * handles activate events in that kind of window.
  748. \******************************************************************************/
  749.  
  750. void DoActivateEvt(
  751.     WindowPtr eventWindow,    /* Window being (de)activated */
  752.     Boolean   becomingActive) /* True if window is becoming activated */
  753. {
  754.     if (IsPictDocWindow( eventWindow ))
  755.         ActivatePictDoc( eventWindow, becomingActive );
  756. }
  757.  
  758.  
  759. /******************************************************************************\
  760. * Private: DoWindowClose - Handle a click in the close box of a window
  761. *
  762. * This routine should be called when the user clicks in the close box of the
  763. * window specified by eventWind.  The mouse is tracked until the user releases
  764. * the mouse button.  If the user released the mouse button while the mouse was
  765. * in the close box, then DoCloseDoc determines the kind of window that the user
  766. * clicked the close box on, and the routine that handles the closing of that
  767. * kind of window is called.  anEvent contains the mouse-down event that was
  768. * determined to be a mouse click in the window.
  769. *
  770. * As new kinds of windows are added to this application, this routine will have
  771. * to be able to detect the new kind of window and dispatch to the routine that
  772. * handles close requests for that kind of window.
  773. \******************************************************************************/
  774.  
  775. static void DoWindowClose(
  776.     EventRecord *anEvent,    /* Mouse-down event in the close box */
  777.     WindowPtr   eventWindow) /* Pointer to the window that was clicked */
  778. {
  779.     if (TrackGoAway( eventWindow, anEvent->where ))
  780.         if (IsPictDocWindow( eventWindow ))
  781.             DoClosePictDoc( eventWindow );
  782. }
  783.  
  784.  
  785. /******************************************************************************\
  786. * Public: ShowAlert
  787. *
  788. * To position the alert before it’s displayed, the ALRT resource is loaded
  789. * before it’s displayed, and its boundsRect is put into the proper position
  790. * through the CenterScreenRect routine.  Because this modifies the ALRT
  791. * resource in memory and because ALRT resources are normally purgeable, it must
  792. * be made unpurgeable until the alert is dismissed.
  793. \******************************************************************************/
  794.  
  795. short ShowAlert(
  796.     short alertType,    /* Type of alert to display */
  797.     short buttonOption, /* Button options for alert */
  798.     short messageClass, /* Class of message to display in alert */
  799.     short messageIndex) /* Index of message to display in alert */
  800. {
  801.     Str255     aMessage;    /* Contents of message to place in alert */
  802.     AlertTHndl alertHandle; /* Handle to the 'ALRT' resource for this alert */
  803.     Rect       alertRect;   /* Rectangle of alert */
  804.     short      itemHit;     /* Item number of clicked item */
  805.     SignedByte savedState;  /* Saves state alertHandle */
  806.  
  807.     /* Put the specified message into the dialog parameter text */
  808.     if (messageIndex != 0)
  809.     {
  810.         GetIndString( /*<*/aMessage, messageClass, messageIndex );
  811.         ParamText( aMessage, "\p", "\p", "\p" );
  812.     }
  813.  
  814.     /* Show the stop alert */
  815.     InitCursor();
  816.  
  817.     /* Center and display the alert */
  818.     alertHandle = (AlertTHndl)Get1Resource( 'ALRT', buttonOption );
  819.     if (alertHandle != nil)
  820.     {
  821.         /* Must make alert unpurgeable because we’re modifying it in memory */
  822.         savedState = HGetState( (Handle)alertHandle );
  823.         HNoPurge( (Handle)alertHandle );
  824.  
  825.         /* Put the rectangle of the alert into alert position */
  826.         alertRect = (**alertHandle).boundsRect;
  827.         PositionScreenRect( /*◊*/&alertRect, kMainScreenPos, kAlertPos,
  828.                 nil, 0, 0 );
  829.         (**alertHandle).boundsRect = alertRect;
  830.  
  831.         /* Present the alert */
  832.         if (alertType == kGenericAlert)
  833.             itemHit = Alert( buttonOption, nil );
  834.         else if (alertType == kNoteAlert)
  835.             itemHit = NoteAlert( buttonOption, nil );
  836.         else if (alertType == kCautionAlert)
  837.             itemHit = CautionAlert( buttonOption, nil );
  838.         else if (alertType == kStopAlert)
  839.             itemHit = StopAlert( buttonOption, nil );
  840.  
  841.         /* Restore the state of alertHandle */
  842.         HSetState( (Handle)alertHandle, savedState );
  843.     }
  844.  
  845.     return itemHit;
  846. }
  847.  
  848.  
  849. /******************************************************************************\
  850. * Public: TrapExists
  851. *
  852. * Traps with trap word of $AAXX or $ABXX are treated as being identical to $A8XX
  853. * and $A9XX if Color QuickDraw isn’t implemented, so we check for this case
  854. * first.  We explicitly check to see if the trap word has a value greater than
  855. * the largest possible trap word on this machine.  If it is, then the trap is
  856. * automatically considered to be unimplemented.
  857. \******************************************************************************/
  858.  
  859. Boolean TrapExists(
  860.     short theTrap) /* Trap word being tested */
  861. {
  862.     TrapType theTrapType; /* The trap type of theTrap */
  863.  
  864.     /* If it’s a CQD trap but the trap table is too small, assume unimp. */
  865.     theTrapType = GetTrapType( theTrap );
  866.     if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >=
  867.             MaxToolboxTrap()))
  868.         theTrap = _Unimplemented;
  869.  
  870.     /* Return true if trap is implemented */
  871.     return NGetTrapAddress( _Unimplemented, ToolTrap ) !=
  872.             NGetTrapAddress( theTrap, theTrapType );
  873. }
  874.  
  875.  
  876. /******************************************************************************\
  877. * Private: MaxToolboxTrap - Determine max trap number available
  878. *
  879. * Depending upon whether Color QuickDraw is implemented, the maximum trap number
  880. * is either $0200 or $0400.  This routine tests to see which is the case by
  881. * testing _InitGraf (trap $A86E) against trap $AA6E.  If the trap table is the
  882. * bigger one, trap $AA6E always points either to Unimplemented or some other
  883. * trap.  If the trap table is the smaller one, then $AA6E evaluates to the same
  884. * trap as _InitGraf.  by comparing the address of the InitGraf trap against the
  885. * address of the $AA6E trap, we can determine whether the trap table is the
  886. * bigger one or the smaller one.  If we have the bigger trap table, then $0400
  887. * is returned.  If it’s the smaller trap table, then $0200 is returned.
  888. *
  889. * Some of you might think that it’s be a lot simpler by testing to see whether
  890. * Color QuickDraw is implemented or not.  Actually, I kind of think so too, but
  891. * there are changes to the system software version 7.0 trap dispatcher that
  892. * might make that test invalid, so I don’t know.  I didn’t write this, I just
  893. * use it.
  894. \******************************************************************************/
  895.  
  896. static short MaxToolboxTrap()
  897. {
  898.     if (NGetTrapAddress( _InitGraf, ToolTrap ) ==
  899.             NGetTrapAddress(0xAA6E, ToolTrap))
  900.         return 0x0200;
  901.     else
  902.         return 0x0400;
  903. }
  904.  
  905.  
  906. /******************************************************************************\
  907. * Private: GetTrapType - Determine whether a trap is OS trap or Toolbox trap
  908. *
  909. * This routine tests to see whether the trap specified by theTrap is an
  910. * operating system trap or a toolbox trap.  Operating system trap words begin
  911. * with $A0 or $A1 while toolbox traps begin with $A8, $A9, $AA, or $AB.  By
  912. * simply testing bit 11 of the trap word, we can determine which kind of trap
  913. * theTrap is.  If it’s an operating system trap, then OSTrap is returned.  If
  914. * it’s a toolbox trap, then ToolTrap is returned.
  915. \******************************************************************************/
  916.  
  917. static TrapType GetTrapType(
  918.     short theTrap) /* Trap word being tested */
  919. {
  920.     /* OS traps start with A0 or A1, Toolbox traps with A8, A9, AA, or AB */
  921.     if ((theTrap & 0x0800) == 0)
  922.         return OSTrap;
  923.     else
  924.         return ToolTrap;
  925. }
  926.  
  927.  
  928. /******************************************************************************\
  929. * Public: FileSpecGet
  930. *
  931. \******************************************************************************/
  932.  
  933. Boolean FileSpecGet(
  934.     FileFilterProcPtr fileFilter, /* Pointer to routine to filter files */
  935.     short             numTypes,   /* Number of files types in typeList */
  936.     SFTypeList        typeList,   /* Type of files to offer */
  937.     StandardFileReply *retReply)  /* Returns information about file to get */
  938. {
  939.     DialogTHndl sfTemplate;  /* Template for Standard File dialog */
  940.     Rect        sfRect;      /* Rectangle of Standard File dialog */
  941.     SFReply     oldReply;    /* Old-style reply record */
  942.  
  943.     if (gHasCoolSF)
  944.         StandardGetFile( NewFileFilterProc(fileFilter), numTypes, typeList, /*<*/retReply );
  945.     else
  946.     {
  947.         /* Center the rectangle of the Standard File dialog */
  948.         sfTemplate = (DialogTHndl)GetResource( 'DLOG', getDlgID );
  949.         sfRect = (**sfTemplate).boundsRect;
  950.         PositionScreenRect( &sfRect, kMainScreenPos, kAlertPos,
  951.                 nil, 0, 0 );
  952.  
  953.         /* Present the Standard File dialog */
  954.         SFGetFile( topLeft( sfRect ), "\p", NewFileFilterProc(fileFilter), numTypes, typeList, nil,
  955.                 /*<*/&oldReply );
  956.  
  957.         /* Convert the old reply to a new reply record */
  958.         (void)ConvertOldToNewSFReply( &oldReply, retReply );
  959.     }
  960.     return retReply->sfGood;
  961. }
  962.  
  963.  
  964. /******************************************************************************\
  965. * Public: ConvertOldToNewSFReply
  966. *
  967. * GetWDInfo is used to convert the working directory reference number that’s
  968. * in the oldReply->vRefNum field to a real volume reference number and directory
  969. * ID so that these values can be stuffed into the new reply record’s FSSpec.
  970. \******************************************************************************/
  971.  
  972. OSErr ConvertOldToNewSFReply(
  973.     SFReply           *oldReply, /* Old reply record to be converted */
  974.     StandardFileReply *newReply) /* Returns the converted reply record */
  975. {
  976.     short   volRef;     /* Volume ref number (NOT WD ref num) of file */
  977.     long    dirID;      /* Directory ID of the file */
  978.     long    procID;     /* WD Proc ID; ignored */
  979.     FInfo   finderInfo; /* Finder info for a file; ignored */
  980.     Boolean replacing;  /* True if the specified file exists */
  981.     OSErr   error;
  982.  
  983.     /* Get the real volume reference number of directory ID of file */
  984.     error = GetWDInfo( oldReply->vRefNum, /*<*/&volRef,
  985.             /*<*/&dirID, /*<*/&procID );
  986.     if (error != noErr)
  987.         return error;
  988.  
  989.     /* Probe to see if the specified file exists */
  990.     error = HGetFInfo( volRef, dirID, oldReply->fName, /*<*/&finderInfo ); 
  991.     if (error == fnfErr)
  992.         replacing = false;
  993.     else if (error == noErr)
  994.         replacing = true;
  995.     else
  996.         return error;
  997.  
  998.     /* Fill out the new reply record */
  999.     newReply->sfGood = oldReply->good;
  1000.     newReply->sfReplacing = replacing;
  1001.     newReply->sfType = oldReply->fType;
  1002.     newReply->sfFile.vRefNum = volRef;
  1003.     newReply->sfFile.parID = dirID;
  1004.     BlockMove( (Ptr)&oldReply->fName, (Ptr)&newReply->sfFile.name,
  1005.             oldReply->fName[0] + 1 );
  1006.     newReply->sfScript = iuSystemScript;
  1007.     newReply->sfFlags = 0;
  1008.     newReply->sfIsFolder = false;
  1009.     newReply->sfIsVolume = false;
  1010.     newReply->sfReserved1 = 0;
  1011.     newReply->sfReserved2 = 0;
  1012.  
  1013.     return noErr;
  1014. }
  1015.  
  1016.  
  1017. /******************************************************************************\
  1018. * Public: EqualFSSpec
  1019. *
  1020. * To compare names, I’m using EqualString with no case sensitivity, but with
  1021. * sensitivity to diacriticals.  This isn’t usually the recommended way of
  1022. * comparing strings, because the Script Manager has routines for comparing
  1023. * strings in a more sophisticated, localizable way.  But the File Manager uses
  1024. * _CmpString, which is the assembly language equivalent of EqualString, so
  1025. * that’s the way I must do things here.
  1026. \******************************************************************************/
  1027.  
  1028. Boolean EqualFSSpec(
  1029.     FSSpecPtr spec0, /* First FSSpec being compared */
  1030.     FSSpecPtr spec1) /* Second FSSpec being compared */
  1031. {
  1032.     return (spec0->vRefNum == spec1->vRefNum) &&
  1033.            (spec0->parID == spec1->parID) &&
  1034.            (EqualString(spec0->name, spec1->name, !kCaseSens, kDiacSens));
  1035. }
  1036.  
  1037.  
  1038. /******************************************************************************\
  1039. * Public: CmdPeriodEvent
  1040. *
  1041. * This routine uses the technique documented in Macintosh Technical Note #263
  1042. * to determine whether the event passed in the anEvent parameter contains a
  1043. * command-period event or not, regardless of the current keyboard layout.
  1044. *
  1045. * The problem that this routine solves is that some keyboards (mainly some
  1046. * European keyboards) require the shift key to be pressed to generate the
  1047. * period, but the command key turns off the shift key, making it impossible to
  1048. * see the period.  To fix this, this routine calls the KeyTranslate routine which
  1049. * maps a virtual keycode and modifier keys to the ASCII code of the typed
  1050. * character.  The modifier keys passed to KeyTranslate are the same as in the
  1051. * event record, but the command key modifier bit is stripped out.  This makes
  1052. * KeyTranslate think the command key wasn’t held down, and so the influence of other
  1053. * modifier keys is unaffected.
  1054. \******************************************************************************/
  1055.  
  1056. Boolean CmdPeriodEvent(
  1057.     EventRecord *anEvent) /* Event being tested */
  1058. {
  1059.     long    lowChar;      /* Low character of keyInfo */
  1060.     long    highChar;     /* High character of keyInfo */
  1061.     Handle  hKCHR;        /* Handle to the currently-used KCHR */
  1062.     long    keyInfo;      /* Key information returned from KeyTranslate */
  1063.     long    keyScript;    /* Script of the current keyboard */
  1064.     unsigned long    state;        /* State used for KeyTranslate */
  1065.     short   virtualKey;   /* Virtual keycode of the character-generating key */
  1066.     short   keyCode;      /* Keycode of the character-generating key */
  1067.     Boolean gotCmdPeriod; /* True if detected command-. */
  1068.  
  1069.     gotCmdPeriod = false;
  1070.     if (anEvent->what == keyDown || anEvent->what == autoKey)
  1071.     {
  1072.         if (anEvent->modifiers & cmdKey)
  1073.         {
  1074.             /* Get the virtual keycode of the code-generating key */
  1075.             virtualKey = (anEvent->message & keyCodeMask) >> 8;
  1076.  
  1077.             /* Get a copy of the current KCHR */
  1078.             keyScript = GetScriptVariable( GetScriptManagerVariable( smKeyScript ), smScriptKeys);
  1079.             hKCHR = GetResource('KCHR', keyScript);
  1080.             if (hKCHR != nil)
  1081.             {
  1082.                 /* AND out the command key and OR in the virtualKey */
  1083.                 keyCode = (anEvent->modifiers & kMaskModifiers) | virtualKey;
  1084.  
  1085.                 /* Get key information */
  1086.                 state = 0;
  1087.                 keyInfo = KeyTranslate( *hKCHR, keyCode, &state );
  1088.             }
  1089.             else
  1090.                 keyInfo = anEvent->message;
  1091.  
  1092.             /* Check both low and high bytes of keyInfo for period */
  1093.             lowChar = keyInfo & kMaskASCII2;
  1094.             highChar = (keyInfo & kMaskASCII1) >> 16;
  1095.             if (lowChar == '.' || highChar == '.')
  1096.                 gotCmdPeriod = true;
  1097.         }
  1098.     }
  1099.  
  1100.     return gotCmdPeriod;
  1101. }
  1102.  
  1103.  
  1104. /******************************************************************************\
  1105. * Public: FakeButtonHit
  1106. *
  1107. * HiliteControl is used to hilight and unhilight a button.
  1108. \******************************************************************************/
  1109.  
  1110. void FakeButtonHit(
  1111.     ControlHandle buttonControl) /* Handle to button whose click we’re faking */
  1112. {
  1113.     unsigned long lastTicks; /* TickCount at end of delay; ignored */
  1114.  
  1115.     HiliteControl( buttonControl, 1 );
  1116.     Delay( 6, &lastTicks );
  1117.     HiliteControl( buttonControl, 0 );
  1118. }
  1119.  
  1120.  
  1121. /******************************************************************************\
  1122. * NAME & SYNOPSIS:
  1123. * RestoreColorsPalette: Restore all screens to the default color table
  1124. *
  1125. * PARAMETERS:
  1126. * See ColorReset.h
  1127. *
  1128. * DEFINITION:
  1129. * See ColorReset.h
  1130. *
  1131. * DESCRIPTION:
  1132. * To change the color table of any screen using the Palette Manager, a window
  1133. * must be used.  But all we want to do is reset the color tables, not display a
  1134. * window.  The obvious solution is to make a very small, inconspicuous window
  1135. * that’s tough to notice, and that’s what RestoreColorsPalette does.  A 1 pixel
  1136. * by 1 pixel is created, and a 1-entry palette is made and attached to the
  1137. * window, just so that it has a palette that can be set to the right size and
  1138. * colors later.
  1139. *
  1140. * Each screen can have different depths, and each can be gray-scale or colors,
  1141. * so every screen has have its colors set individually.  Since all we have is a
  1142. * 1 pixel by 1 pixel window, there’s not much choice here anyway.  To run
  1143. * through each screen, the GDevice list is used.  The GDevice list is a linked
  1144. * list of GDevice records that the system maintains, and there’s one GDevice
  1145. * record for every screen that’s attached to a Macintosh.  Each screen’s GDevice
  1146. * can be used to find out the screen’s depth, and whether it’s set to Grays or
  1147. * Colors mode.  See the Graphics Device Manager chapter of Inside Macintosh
  1148. * Volume VI for details. GetDeviceList is used to find the first GDevice in the
  1149. * GDevice list, and GetNextDevice is used to get the next GDevice list the list.
  1150. *
  1151. * For each GDevice in the list, it’s first tested to see if it belongs to an
  1152. * active screen.  If it doesn’t, then we just ignore it and go to the next
  1153. * GDevice in the list.  If it does, then the GDevice’s PixMap is checked to see
  1154. * what the depth of the screen is.  This depth can be passed to the GetCTable
  1155. * routine (see the Color Manager chapter of Inside Macintosh Volume V for
  1156. * details about this routine) to get a color table filled with the default
  1157. * colors for the screen depth.  As of 32-Bit QuickDraw 1.0 and/or system
  1158. * software version 6.0.5, the color table of a screen is guaranteed to contain
  1159. * the highlight color, and if you add 64 to the pixel depth and pass the result
  1160. * to GetCTable, GetCTable returns a color table filled with the default colors
  1161. * including the highlight color, and so that’s what I pass to GetCTable for a
  1162. * screen set to Colors mode.  For gray-scale screens, you add 32 to the pixel
  1163. * depth to have GetCTable return a color table filled with the default gray-
  1164. * scale color table.
  1165. *
  1166. * I pass whatever color table GetCTable returns to CTab2Palette, and I use a
  1167. * usage mode of pmTolerant + pmExplicit.  This mode is just like pmTolerant, but
  1168. * it guarantees that the palette colors are put into the screen’s color table in
  1169. * the same order that they appear in the palette when that palette is activated.
  1170. * If you just use pmTolerant, the order of colors in the screen’s color table
  1171. * will likely be scrambled, so the screen has the default colors, but not in the
  1172. * default order.
  1173. *
  1174. * Once the palette is set up with the default colors for the screen we’re
  1175. * working on, the 1 pixel by 1 pixel window is moved to the extreme upper-left
  1176. * corner of the screen, then it’s shown and immediately hidden.  The moment the
  1177. * window is shown, the screen’s color table is filled with the default colors in
  1178. * the default order.  Then we move on to the next screen until all screens have
  1179. * been handled.
  1180. *
  1181. * RETURN VALUES:
  1182. * See ColorReset.h
  1183. \******************************************************************************/
  1184.  
  1185. void RestoreColorsPalette()
  1186. {
  1187.     WindowPtr     tinyWindow;    /* Pointer to tiny window */
  1188.     CTabHandle    defaultColors; /* Default color table for the screen */
  1189.     PaletteHandle tinyPalette;   /* Palette to express defaultColors */
  1190.     Rect          tinyRect;      /* Rectangle of tiny window */
  1191.     GDHandle      screenDevice;  /* Handle to each screen’s GDevice */
  1192.     Point         screenCorner;  /* Global coordinate of top-left of each screen */
  1193.     short         clutID;        /* ID of table of default colors */
  1194.  
  1195.     /* Make the tiny window for attaching our palette */
  1196.     SetRect( &tinyRect, 0, 0, 1, 1 );
  1197.     tinyWindow = NewCWindow(
  1198.             nil,
  1199.             &tinyRect,
  1200.             "\p",
  1201.             false,
  1202.             plainDBox,
  1203.             (WindowPtr)-1,
  1204.             false,
  1205.             0L );
  1206.  
  1207.     /* Make a palette; it’s just a placeholder for the moment */
  1208.     tinyPalette = NewPalette( 1, nil, pmTolerant + pmExplicit, 0 );
  1209.     SetPalette( tinyWindow, tinyPalette, false );
  1210.  
  1211.     /* Loop through each screen GDevice to reset its screen’s colors */
  1212.     screenDevice = GetDeviceList();
  1213.     while (screenDevice != nil)
  1214.     {
  1215.         if (TestDeviceAttribute( screenDevice, screenActive ))
  1216.         {
  1217.             /* Grab default color table for the screen */
  1218.             clutID = (**(**screenDevice).gdPMap).pixelSize;
  1219.             if (TestDeviceAttribute (screenDevice, gdDevType ))
  1220.                 clutID += 64;
  1221.             else
  1222.                 clutID += 32;
  1223.             defaultColors = GetCTable( clutID );
  1224.  
  1225.             /* Convert default screen colors to a tolerant palette */
  1226.             CTab2Palette( defaultColors, tinyPalette, pmTolerant + pmExplicit, 0 );
  1227.  
  1228.             /* Don’t need that clut any more */
  1229.             DisposeCTable( defaultColors );
  1230.  
  1231.             /* Move the tiny window into the upper left corner of the screen */
  1232.             screenCorner.h = (**screenDevice).gdRect.left;
  1233.             screenCorner.v = (**screenDevice).gdRect.top;
  1234.             
  1235.             MoveWindow( tinyWindow, screenCorner.h, screenCorner.v, false );
  1236.             ShowWindow( tinyWindow );
  1237.             HideWindow( tinyWindow );
  1238.         }
  1239.  
  1240.     /* Go to the next screen in the device list */
  1241.     screenDevice = GetNextDevice( screenDevice );
  1242.     }
  1243.  
  1244.     /* Get rid of the window and palette */
  1245.     DisposePalette( tinyPalette );
  1246.     DisposeWindow( tinyWindow );
  1247. }
  1248.  
  1249.  
  1250. /******************************************************************************\
  1251. * NAME & SYNOPSIS:
  1252. * RestoreColorsSlam: Restore all screens to the default color table
  1253. *
  1254. * PARAMETERS:
  1255. * See ColorReset.h
  1256. *
  1257. * DEFINITION:
  1258. * See ColorReset.h
  1259. *
  1260. * DESCRIPTION:
  1261. * 32-Bit QuickDraw 1.0 and system software version 6.0.5 introduced a new
  1262. * routine called RestoreDeviceClut which sets the color table of specific
  1263. * screens or all the screens to the default set of colors.  RestoreColorsSlam
  1264. * calls RestoreDeviceClut with a nil parameter, which restores the color table
  1265. * of all attached screens.  At this point, the screen could appear in strange
  1266. * colors because RestoreDeviceClut doesn’t cause update events to cause the
  1267. * screen to be redrawn in the new colors.  So, RestoreColorsSlam forces all the
  1268. * screens to be redrawn by calling the Window Manager routine, PaintBehind.
  1269. * This causes the entire desktop area and all windows to be redrawn.  The only
  1270. * part of the screen that isn’t guaranteed to be redrawn is the menu bar, so
  1271. * DrawMenuBar is called to make sure the menu bar is redrawn in the new colors.
  1272. *
  1273. * RETURN VALUES:
  1274. * See ColorReset.h
  1275. \******************************************************************************/
  1276.  
  1277. void RestoreColorsSlam()
  1278. {
  1279.     RestoreDeviceClut( nil );
  1280.     PaintBehind( nil, GetGrayRgn() );
  1281.     DrawMenuBar();
  1282. }
  1283.